#include <ctime>
#include <iostream>
#include <string>
#include <boost/bind.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/asio.hpp>
using boost::asio::ip::tcp;
#include <set>
using namespace std;
std::string make_daytime_string()
{
	using namespace std; // For time_t, time and ctime;
	time_t now = time(0);
	return ctime(&now);
}
class tcp_connection;
set<tcp_connection *> connections;
class tcp_connection
	: public boost::enable_shared_from_this<tcp_connection>
{
public:
	typedef boost::shared_ptr<tcp_connection> pointer;
	
	static pointer create(boost::asio::io_service& io_service)
	{
		return pointer(new tcp_connection(io_service));
	}
	
	tcp::socket& socket()
	{
		return socket_;
	}
	~tcp_connection()
	{
		cout << "disconnected" << endl;
		connections.erase(this);
	}
	void write()
	{
		if (writing)
			return;
		writing = true;
		message_ = make_daytime_string();
		boost::asio::async_write(socket_, boost::asio::buffer(message_),
			boost::bind(&tcp_connection::handle_write, shared_from_this(),
			boost::asio::placeholders::error,
			boost::asio::placeholders::bytes_transferred));
	}
	void start()
	{
		connections.insert(this);
		data.resize(10);
		boost::asio::async_read(socket_, boost::asio::buffer(&data.at(0), data.size()),
			boost::bind(&tcp_connection::handle_read, shared_from_this(),
			boost::asio::placeholders::error,
			boost::asio::placeholders::bytes_transferred));
		write();
	}

private:
	tcp_connection(boost::asio::io_service& io_service)
		: socket_(io_service), writing(false)
	{
		cout << "accepted" << endl;
	}
	void handle_read(const boost::system::error_code &error,
		size_t bytes_transferred)
	{
		cout << "handle_read" << endl;
		data.resize(10);
		/*
		boost::asio::async_read(socket_, boost::asio::buffer(message_),
			boost::bind(&tcp_connection::handle_read, shared_from_this(),
			boost::asio::placeholders::error,
			boost::asio::placeholders::bytes_transferred));
		*/
	}
	void handle_write(const boost::system::error_code& /*error*/,
		size_t /*bytes_transferred*/)
	{
		/*
		data.resize(10);
		boost::asio::async_read(socket_, boost::asio::buffer(&data.at(0), data.size()),
			boost::bind(&tcp_connection::handle_read, shared_from_this(),
			boost::asio::placeholders::error,
			boost::asio::placeholders::bytes_transferred));
		*/
		writing = false;
	}
	
	tcp::socket socket_;
	bool writing;
	std::string message_;
	std::vector<char> data;
};
class tcp_server
{
public:

	tcp_server(boost::asio::io_service& io_service)
		: acceptor_(io_service, tcp::endpoint(tcp::v4(), 40005))
	{
		start_accept();
	}

private:

	void start_accept()
	{
		tcp_connection::pointer new_connection =
			tcp_connection::create(acceptor_.io_service());
		
		acceptor_.async_accept(new_connection->socket(),
			boost::bind(&tcp_server::handle_accept, this, new_connection,
			boost::asio::placeholders::error));
	}
	
	void handle_accept(tcp_connection::pointer new_connection,
		const boost::system::error_code& error)
	{
		if (!error)
		{
			new_connection->start();
			start_accept();
		}
	}
	tcp::acceptor acceptor_;
};

int main()
{
	try
	{
		boost::asio::io_service io_service;
		tcp_server server(io_service);
		//io_service.run();
		for(;;) {		
			io_service.run_one();
			set<tcp_connection *>::iterator i = connections.begin();
			for(; i != connections.end(); i++) {
				tcp_connection *conn = *i;
				conn->write();
			}
		}
	}
	catch (std::exception& e)
	{
		std::cerr << e.what() << std::endl;
	}
	
	return 0;
}

